001 /*
002 * Copyright 2005 Stephen J. McConnell.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
013 * implied.
014 *
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018
019 package net.dpml.lang;
020
021 import java.beans.Expression;
022 import java.io.Serializable;
023 import java.lang.reflect.Field;
024 import java.lang.reflect.Array;
025 import java.util.ArrayList;
026 import java.util.Arrays;
027 import java.util.Map;
028
029 import net.dpml.util.PropertyResolver;
030
031 /**
032 * A object resolvable from primitive arguments.
033 *
034 * @author <a href="http://www.dpml.net">Digital Product Meta Library</a>
035 * @version 1.0.2
036 */
037 public class Construct implements Value, Serializable
038 {
039 /**
040 * Serial version identifier.
041 */
042 static final long serialVersionUID = 1L;
043
044 /**
045 * Utility operation that consolidates an array of values and supplimentary
046 * arguments to an array of objects.
047 *
048 * @param map a map of keys and values used in symbolic target resolution
049 * @param params the value array
050 * @param args supplimentary arguments
051 * @return the consolidated argument array
052 * @exception Exception if an error occurs in argument resolution
053 */
054 public static Object[] getArgs( Map map, Value[] params, Object[] args ) throws Exception
055 {
056 ArrayList list = new ArrayList();
057 for( int i=0; i < params.length; i++ )
058 {
059 Value value = params[i];
060 Object object = value.resolve( map );
061 if( null != object )
062 {
063 list.add( object );
064 }
065 }
066 for( int i=0; i < args.length; i++ )
067 {
068 Object value = args[i];
069 if( null != value )
070 {
071 list.add( value );
072 }
073 }
074 return list.toArray();
075 }
076
077 private final String m_method;
078 private final String m_target;
079 private final String m_value;
080 private final Value[] m_args;
081 private final boolean m_compound;
082
083 /**
084 * Create a new construct using the default java.lang.String class as the base type.
085 * @param value the construct value
086 */
087 public Construct( String value )
088 {
089 this( null, null, value );
090 }
091
092 /**
093 * Create a new construct using a supplied target defintion. The target argument
094 * may be either a classname or a symbolic reference in the form ${[key]}. If the
095 * argument is symbolic it resolved relative to a context map supplied by the
096 * application resolving construct values.
097 *
098 * @param target a classname or symbolic reference
099 * @param value the construct value
100 */
101 public Construct( String target, String value )
102 {
103 this( target, null, value );
104 }
105
106 /**
107 * Create a new construct using a supplied target defintion. The target argument
108 * may be either a classname or a symbolic reference in the form ${[key]}. If the
109 * argument is symbolic it is resolved relative to a context map supplied by the
110 * application resolving construct values. If the construct value is symbolic
111 * the implementation will attempt to expand the reference relative to a context
112 * map (if supplied) otherwise the implementation will attempt to expand the value
113 * using system properties.
114 *
115 * @param target a classname or symbolic reference
116 * @param method the method to invoke on the target
117 * @param value the construct value
118 */
119 public Construct( String target, String method, String value )
120 {
121 m_target = target;
122 m_method = method;
123 m_value = value;
124 m_args = new Value[0];
125 m_compound = false;
126 }
127
128 /**
129 * Create a new construct using a supplied target defintion. The target argument
130 * may be either a classname or a symbolic reference in the form ${[key]}. If the
131 * argument is symbolic it is resolved relative to a context map supplied by the
132 * application resolving construct values. Instance values resolved from the
133 * supplied Value[] will be used as constructor arguments when resolving the target.
134 *
135 * @param target the construct classname
136 * @param args an array of unresolved parameter values
137 */
138 public Construct( String target, Value[] args )
139 {
140 this( target, null, args );
141 }
142
143 /**
144 * Create a new construct using a supplied target defintion. The target argument
145 * may be either a classname or a symbolic reference in the form ${[key]}. If the
146 * argument is symbolic it is resolved relative to a context map supplied by the
147 * application resolving construct values. Instance values resolved from the
148 * supplied Value[] will be used as method arguments when resolving the target.
149 *
150 * @param target the construct classname
151 * @param method the method to invoke on the target
152 * @param args an array of unresolved parameter values
153 */
154 public Construct( String target, String method, Value[] args )
155 {
156 if( null == args )
157 {
158 m_args = new Value[0];
159 }
160 else
161 {
162 m_args = args;
163 }
164 m_value = null;
165 m_target = target;
166 m_method = method;
167 m_compound = true;
168 }
169
170 /**
171 * Creation of a new construct using a value directive.
172 * @param directive the value directive
173 */
174 public Construct( ValueDirective directive )
175 {
176 m_value = directive.getBaseValue();
177 m_target = directive.getTargetExpression();
178 m_method = directive.getMethodName();
179 m_compound = directive.isCompound();
180 ValueDirective[] values = directive.getValueDirectives();
181 int n = values.length;
182 m_args = new Value[ n ];
183 for( int i=0; i<n; i++ )
184 {
185 ValueDirective value = values[i];
186 m_args[i] = new Construct( value );
187 }
188 }
189
190 /**
191 * Return TRUE if this construct is a compund construct else FALSE.
192 * @return TRUE if this ia a compound construct
193 */
194 public boolean isCompound()
195 {
196 return m_compound;
197 }
198
199 /**
200 * Return the method name to be applied to the target object.
201 * @return the method name
202 */
203 public String getMethodName()
204 {
205 return m_method;
206 }
207
208 /**
209 * Return the set of nested values within this value.
210 * @return the nested values array
211 */
212 public Value[] getValues()
213 {
214 return m_args;
215 }
216
217 /**
218 * Return the classname of the resolved value.
219 * @return the classname
220 */
221 public String getBaseValue()
222 {
223 return m_value;
224 }
225
226 /**
227 * Return the classname of the resolved value.
228 * @return the classname
229 */
230 public String getTargetExpression()
231 {
232 return m_target;
233 }
234
235 /**
236 * Resolve an instance from the value using the context classloader.
237 * @return the resolved instance
238 * @exception Exception if an error occurs during value resolution
239 */
240 public Object resolve() throws Exception
241 {
242 return resolve( null );
243 }
244
245 /**
246 * Resolve an instance from the value using a supplied map.
247 * @param map the context map
248 * @return the resolved instance
249 * @exception Exception if an error occurs during value resolution
250 */
251 public Object resolve( Map map ) throws Exception
252 {
253 return resolve( map, false );
254 }
255
256 /**
257 * Resolve an instance from the value using a supplied isolation policy.
258 * @param isolate the isolation policy
259 * @return the resolved instance
260 * @exception Exception if an error occurs during value resolution
261 */
262 public Object resolve( boolean isolate ) throws Exception
263 {
264 return resolve( null, isolate );
265 }
266
267 /**
268 * Resolve an instance from the value using a supplied context map. If any
269 * target expressions in immediate or nested values contain a symbolic
270 * expression the value will be resolved using the supplied map.
271 *
272 * @param map the context map
273 * @param isolate the isolation policy
274 * @return the resolved instance
275 * @exception Exception if error occurs during instance resolution
276 */
277 public Object resolve( Map map, boolean isolate ) throws Exception
278 {
279 return resolve( null, map, null, isolate );
280 }
281
282 /**
283 * Resolve an instance from the value using a supplied context map. If any
284 * target expressions in immediate or nested values contain a symbolic
285 * expression the value will be resolved using the supplied map.
286 *
287 * @param classname the default classname
288 * @param map the context map
289 * @param isolate the isolation policy
290 * @return the resolved instance
291 * @exception Exception if error occurs during instance resolution
292 */
293 public Object resolve( String classname, Map map, boolean isolate ) throws Exception
294 {
295 return resolve( classname, map, null, isolate );
296 }
297
298 /**
299 * Resolve an instance from the value.
300 * @param map the context map
301 * @param classloader the classloader to use
302 * @param isolate the isolation policy
303 * @return the resolved instance
304 * @exception Exception if an error occurs during value resolution
305 */
306 private Object resolve( String classname, Map map, ClassLoader classloader, boolean isolate ) throws Exception
307 {
308 ClassLoader loader = resolveClassLoader( classloader );
309 Object target = getTargetObject( classname, map, loader );
310 if( isCompound() )
311 {
312 if( null == target )
313 {
314 throw new NullPointerException( "target" );
315 }
316 else
317 {
318 return resolveCompoundExpression( target, map, loader );
319 }
320 }
321 else
322 {
323 Object value = resolveBaseValue( map );
324 if( null == target )
325 {
326 return value;
327 }
328 else
329 {
330 return resolveSimpleExpression( target, map, loader );
331 }
332 }
333 }
334
335 private Object resolveBaseValue( Map map )
336 {
337 return expandSymbols( map, m_value );
338 }
339
340 private Object resolveSimpleExpression( Object target, Map map, ClassLoader classloader ) throws Exception
341 {
342 String method = getMethodName();
343 Object value = expandSymbols( map, m_value );
344 boolean isaClass = ( target.getClass() == Class.class );
345 if( null == method )
346 {
347 if( isaClass )
348 {
349 method = "new";
350 }
351 else
352 {
353 final String error =
354 "Target expression '"
355 + m_target
356 + "' resolving to an instance of the class ["
357 + target.getClass()
358 + "] canot be resolved due to missing method declaration.";
359 throw new ValueException( error );
360 }
361 }
362 else
363 {
364 if( isaClass && ( null == value ) )
365 {
366 // check if the method name is a static field
367 Class c = (Class) target;
368 try
369 {
370 Field field = c.getField( method );
371 return field.get( c );
372 }
373 catch( NoSuchFieldException e )
374 {
375 // assume its a method
376 }
377 }
378 }
379
380 if( value == null )
381 {
382 Expression expression = new Expression( target, method, new Object[0] );
383 try
384 {
385 return expression.getValue();
386 }
387 catch( Throwable e )
388 {
389 final String error =
390 "Internal error while evalating simple expression using:"
391 + "\n target: "
392 + m_target
393 + " ("
394 + target
395 + ")"
396 + "\n method: "
397 + m_method
398 + " ("
399 + method
400 + ")";
401 throw new ValueException( error, e );
402 }
403 }
404 else
405 {
406 Expression expression = new Expression( target, method, new Object[]{value} );
407 try
408 {
409 return expression.getValue();
410 }
411 catch( Throwable e )
412 {
413 final String error =
414 "Internal error while evaluating expression using:"
415 + "\n target: " + m_target + " (" + target + ")"
416 + "\n method: " + m_method + " (" + method + ")"
417 + "\n value: " + m_value + " (" + value.getClass().getName() + ")";
418 throw new ValueException( error, e );
419 }
420 }
421 }
422
423 private Object resolveCompoundExpression( Object target, Map map, ClassLoader classloader ) throws Exception
424 {
425 Value[] args = getValues();
426 Object[] instances = getInstanceValues( map, classloader, args );
427 String method = getMethodName();
428 boolean isaClass = ( target.getClass() == Class.class );
429
430 //
431 // check if we are dealing with an array class and if so return and
432 // array created from the array of nested values
433 //
434
435 if( isaClass )
436 {
437 Class c = (Class) target;
438 if( c.isArray() )
439 {
440 Class type = c.getComponentType();
441 if( type.isPrimitive() )
442 {
443 return buildPrimitiveArray( type, instances );
444 }
445 else
446 {
447 Object[] result =
448 (Object[]) Array.newInstance( type, instances.length );
449 for( int i=0; i<instances.length; i++ )
450 {
451 Object instance = instances[i];
452 if( type.isAssignableFrom( instance.getClass() ) )
453 {
454 result[i] = instances[i];
455 }
456 else
457 {
458 final String error =
459 "Array ["
460 + type.getName()
461 + "] contains an invalid element ["
462 + instance.getClass().getName()
463 + "].";
464 throw new ValueException( error );
465 }
466 }
467 return result;
468 }
469 }
470 }
471
472 // otherwise its a regular expression
473
474 if( null == method )
475 {
476 if( isaClass )
477 {
478 method = "new";
479 }
480 else
481 {
482 final String error =
483 "Missing method declaration in a composite value construct."
484 + "\nTarget: "
485 + target
486 + " (" + target.getClass().getName()
487 + ")";
488 throw new ValueException( error );
489 }
490 }
491 else
492 {
493 if( isaClass && ( instances.length == 0 ) )
494 {
495 // check if the method name is a static field
496 Class c = (Class) target;
497 try
498 {
499 Field field = c.getField( method );
500 return field.get( c );
501 }
502 catch( NoSuchFieldException e )
503 {
504 // assume its a method
505 }
506 }
507 }
508 Expression expression = new Expression( target, method, instances );
509 try
510 {
511 return expression.getValue();
512 }
513 catch( Throwable e )
514 {
515 StringBuffer buffer = new StringBuffer();
516 buffer.append( "Internal error while evaluating compound expression." );
517 buffer.append( "\n target: " + m_target + " (" + target + ")" );
518 buffer.append( "\n method: " + m_method + " (" + method + ")" );
519 for( int i=0; i<instances.length; i++ )
520 {
521 buffer.append(
522 "\n param "
523 + ( i+1 )
524 + ": "
525 + instances[i].getClass().getName()
526 );
527 }
528 String error = buffer.toString();
529 throw new ValueException( error, e );
530 }
531 }
532
533 private Object buildPrimitiveArray( Class type, Object[] instances ) throws ValueException
534 {
535 Object result = Array.newInstance( type, instances.length );
536 if( Integer.TYPE == type )
537 {
538 return buildIntArray( instances );
539 }
540 else if( Short.TYPE == type )
541 {
542 return buildShortArray( instances );
543 }
544 else if( Long.TYPE == type )
545 {
546 return buildLongArray( instances );
547 }
548 else if( Byte.TYPE == type )
549 {
550 return buildByteArray( instances );
551 }
552 else if( Double.TYPE == type )
553 {
554 return buildDoubleArray( instances );
555 }
556 else if( Float.TYPE == type )
557 {
558 return buildFloatArray( instances );
559 }
560 else if( Character.TYPE == type )
561 {
562 return buildCharacterArray( instances );
563 }
564 else if( Boolean.TYPE == type )
565 {
566 return buildBooleanArray( instances );
567 }
568 else
569 {
570 final String error =
571 "Primitive array class ["
572 + type.getName()
573 + "] is not recognized.";
574 throw new UnsupportedOperationException( error );
575 }
576 }
577
578 private Object buildIntArray( Object[] instances ) throws ValueException
579 {
580 Object result = Array.newInstance( Integer.TYPE, instances.length );
581 for( int i=0; i<instances.length; i++ )
582 {
583 Object instance = instances[i];
584 if( instance instanceof Integer )
585 {
586 Integer integer = (Integer) instance;
587 int v = integer.intValue();
588 Array.setInt( result, i, v );
589 }
590 else
591 {
592 final String error =
593 "Supplied int array argument class ["
594 + instance.getClass().getName()
595 + "] is not an Integer.";
596 throw new ValueException( error );
597 }
598 }
599 return result;
600 }
601
602 private Object buildShortArray( Object[] instances ) throws ValueException
603 {
604 Object result = Array.newInstance( Short.TYPE, instances.length );
605 for( int i=0; i<instances.length; i++ )
606 {
607 Object instance = instances[i];
608 if( instance instanceof Short )
609 {
610 Short primitive = (Short) instance;
611 short v = primitive.shortValue();
612 Array.setShort( result, i, v );
613 }
614 else
615 {
616 final String error =
617 "Supplied short array argument class ["
618 + instance.getClass().getName()
619 + "] is not an Short.";
620 throw new ValueException( error );
621 }
622 }
623 return result;
624 }
625
626 private Object buildLongArray( Object[] instances ) throws ValueException
627 {
628 Object result = Array.newInstance( Long.TYPE, instances.length );
629 for( int i=0; i<instances.length; i++ )
630 {
631 Object instance = instances[i];
632 if( instance instanceof Long )
633 {
634 Long primitive = (Long) instance;
635 long v = primitive.longValue();
636 Array.setLong( result, i, v );
637 }
638 else
639 {
640 final String error =
641 "Supplied long array argument class ["
642 + instance.getClass().getName()
643 + "] is not an instance of Long.";
644 throw new ValueException( error );
645 }
646 }
647 return result;
648 }
649
650 private Object buildByteArray( Object[] instances ) throws ValueException
651 {
652 Object result = Array.newInstance( Byte.TYPE, instances.length );
653 for( int i=0; i<instances.length; i++ )
654 {
655 Object instance = instances[i];
656 if( instance instanceof Byte )
657 {
658 Byte primitive = (Byte) instance;
659 byte v = primitive.byteValue();
660 Array.setByte( result, i, v );
661 }
662 else
663 {
664 final String error =
665 "Supplied byte array argument class ["
666 + instance.getClass().getName()
667 + "] is not an instance of Byte.";
668 throw new ValueException( error );
669 }
670 }
671 return result;
672 }
673
674 private Object buildDoubleArray( Object[] instances ) throws ValueException
675 {
676 Object result = Array.newInstance( Double.TYPE, instances.length );
677 for( int i=0; i<instances.length; i++ )
678 {
679 Object instance = instances[i];
680 if( instance instanceof Double )
681 {
682 Double primitive = (Double) instance;
683 double v = primitive.doubleValue();
684 Array.setDouble( result, i, v );
685 }
686 else
687 {
688 final String error =
689 "Supplied double array argument class ["
690 + instance.getClass().getName()
691 + "] is not an instance of Double.";
692 throw new ValueException( error );
693 }
694 }
695 return result;
696 }
697
698 private Object buildFloatArray( Object[] instances ) throws ValueException
699 {
700 Object result = Array.newInstance( Float.TYPE, instances.length );
701 for( int i=0; i<instances.length; i++ )
702 {
703 Object instance = instances[i];
704 if( instance instanceof Float )
705 {
706 Float primitive = (Float) instance;
707 float v = primitive.floatValue();
708 Array.setFloat( result, i, v );
709 }
710 else
711 {
712 final String error =
713 "Supplied float array argument class ["
714 + instance.getClass().getName()
715 + "] is not an instance of Float.";
716 throw new ValueException( error );
717 }
718 }
719 return result;
720 }
721
722 private Object buildCharacterArray( Object[] instances ) throws ValueException
723 {
724 Object result = Array.newInstance( Character.TYPE, instances.length );
725 for( int i=0; i<instances.length; i++ )
726 {
727 Object instance = instances[i];
728 if( instance instanceof Character )
729 {
730 Character primitive = (Character) instance;
731 char v = primitive.charValue();
732 Array.setChar( result, i, v );
733 }
734 else
735 {
736 final String error =
737 "Supplied char array argument class ["
738 + instance.getClass().getName()
739 + "] is not an instance of Character.";
740 throw new ValueException( error );
741 }
742 }
743 return result;
744 }
745
746 private Object buildBooleanArray( Object[] instances ) throws ValueException
747 {
748 Object result = Array.newInstance( Boolean.TYPE, instances.length );
749 for( int i=0; i<instances.length; i++ )
750 {
751 Object instance = instances[i];
752 if( instance instanceof Boolean )
753 {
754 Boolean primitive = (Boolean) instance;
755 boolean v = primitive.booleanValue();
756 Array.setBoolean( result, i, v );
757 }
758 else
759 {
760 final String error =
761 "Supplied boolean array argument class ["
762 + instance.getClass().getName()
763 + "] is not an instance of Boolean.";
764 throw new ValueException( error );
765 }
766 }
767 return result;
768 }
769
770 private Object[] getInstanceValues(
771 Map map, ClassLoader classloader, Value[] args ) throws Exception
772 {
773 Object[] instances = new Object[ args.length ];
774 for( int i=0; i < args.length; i++ )
775 {
776 Value value = args[i];
777 if( value instanceof Construct )
778 {
779 Construct construct = (Construct) value;
780 instances[i] = construct.resolve( null, map, classloader, false );
781 }
782 else
783 {
784 instances[i] = value.resolve( map );
785 }
786 }
787 return instances;
788 }
789
790 private Object expandSymbols( Map map, String value )
791 {
792 if( null == value )
793 {
794 return null;
795 }
796 else
797 {
798 return parseSymbolicValue( map, value );
799 }
800 }
801
802 private Object parseSymbolicValue( Map map, String value )
803 {
804 if( null == map )
805 {
806 return PropertyResolver.resolve( value );
807 }
808 if( value.startsWith( "${" ) && value.endsWith( "}" ) )
809 {
810 String pre = value.substring( 2 );
811 String key = pre.substring( 0, pre.length() -1 );
812 if( map.containsKey( key ) )
813 {
814 return map.get( key );
815 }
816 else
817 {
818 return PropertyResolver.resolve( value );
819 }
820 }
821 else
822 {
823 return PropertyResolver.resolve( value );
824 }
825 }
826
827 /**
828 * Return the instance class using the context classloader.
829 * @return the target object or class
830 * @exception ValueException if target related error occurs
831 */
832 private Object getTargetObject( String classname, Map map, ClassLoader loader ) throws ValueException
833 {
834 if( null == m_target )
835 {
836 return getTargetObject( map, loader, classname );
837 }
838 else
839 {
840 return getTargetObject( map, loader, m_target );
841 }
842 }
843
844 /**
845 * Return the instance class using the context classloader.
846 * @return the target object or class
847 * @exception ValueException if target related error occurs
848 */
849 private Object getTargetObject( Map map, ClassLoader loader, String target ) throws ValueException
850 {
851 if( null == target )
852 {
853 return null;
854 }
855 else if( target.startsWith( "${" ) )
856 {
857 if( null != map )
858 {
859 String pre = target.substring( 2 );
860 String key = pre.substring( 0, pre.length() -1 );
861 if( map.containsKey( key ) )
862 {
863 return map.get( key );
864 }
865 else
866 {
867 final String error =
868 "Unresolvable target symbolic expression ["
869 + target
870 + "].";
871 throw new ValueException( error );
872 }
873 }
874 else
875 {
876 String resolved = PropertyResolver.resolve( target );
877 return getTargetObject( map, loader, resolved );
878 }
879 }
880 else
881 {
882 if( target.endsWith( "[]" ) )
883 {
884 int n = target.length() - 2;
885 String componentClassname = target.substring( 0, n );
886 Class componentClass = resolveType( loader, componentClassname );
887 return Array.newInstance( componentClass, 0 ).getClass();
888 }
889 else
890 {
891 return resolveClass( loader, target );
892 }
893 }
894 }
895
896 /**
897 * Return the instance class using the context classloader.
898 * @return the class
899 * @exception ComponentException if the parameter class cannot be resolved
900 */
901 private Class resolveClass( ClassLoader loader, String classname ) throws ValueException
902 {
903 try
904 {
905 return loader.loadClass( classname );
906 }
907 catch( final ClassNotFoundException e )
908 {
909 if( classname.equals( "int" ) )
910 {
911 return Integer.class;
912 }
913 else if( classname.equals( "short" ) )
914 {
915 return Short.class;
916 }
917 else if( classname.equals( "long" ) )
918 {
919 return Long.class;
920 }
921 else if( classname.equals( "byte" ) )
922 {
923 return Byte.class;
924 }
925 else if( classname.equals( "double" ) )
926 {
927 return Double.class;
928 }
929 else if( classname.equals( "float" ) )
930 {
931 return Float.class;
932 }
933 else if( classname.equals( "char" ) )
934 {
935 return Character.class;
936 }
937 else if( classname.equals( "boolean" ) )
938 {
939 return Boolean.class;
940 }
941 else
942 {
943 final String error =
944 "Class not found ["
945 + classname
946 + "].";
947 throw new ValueException( error, e );
948 }
949 }
950 }
951
952 /**
953 * Return the instance class using the context classloader.
954 * @return the class
955 * @exception ComponentException if the parameter class cannot be resolved
956 */
957 private Class resolveType( ClassLoader loader, String classname ) throws ValueException
958 {
959 try
960 {
961 return loader.loadClass( classname );
962 }
963 catch( final ClassNotFoundException e )
964 {
965 if( classname.equals( "int" ) )
966 {
967 return Integer.TYPE;
968 }
969 else if( classname.equals( "short" ) )
970 {
971 return Short.TYPE;
972 }
973 else if( classname.equals( "long" ) )
974 {
975 return Long.TYPE;
976 }
977 else if( classname.equals( "byte" ) )
978 {
979 return Byte.TYPE;
980 }
981 else if( classname.equals( "double" ) )
982 {
983 return Double.TYPE;
984 }
985 else if( classname.equals( "float" ) )
986 {
987 return Float.TYPE;
988 }
989 else if( classname.equals( "char" ) )
990 {
991 return Character.TYPE;
992 }
993 else if( classname.equals( "boolean" ) )
994 {
995 return Boolean.TYPE;
996 }
997 else
998 {
999 final String error =
1000 "Class not found ["
1001 + classname
1002 + "].";
1003 throw new ValueException( error, e );
1004 }
1005 }
1006 }
1007
1008 private ClassLoader resolveClassLoader( ClassLoader classloader )
1009 {
1010 if( null != classloader )
1011 {
1012 return classloader;
1013 }
1014 else
1015 {
1016 ClassLoader loader = Thread.currentThread().getContextClassLoader();
1017 if( null == loader )
1018 {
1019 return Construct.class.getClassLoader();
1020 }
1021 else
1022 {
1023 return loader;
1024 }
1025 }
1026 }
1027
1028 /**
1029 * Return a string representation of the construct.
1030 * @return the string value
1031 */
1032 public String toString()
1033 {
1034 if( !m_compound )
1035 {
1036 return "construct "
1037 + " target: " + m_target
1038 + " method: " + m_method
1039 + " value: " + m_value;
1040 }
1041 else
1042 {
1043 return "construct "
1044 + " target: " + m_target
1045 + " method: " + m_method
1046 + " values: " + m_args.length;
1047 }
1048 }
1049
1050 /**
1051 * Compare this instance with a supplied object for equality.
1052 * @param other the other object
1053 * @return true if the supplied instance is equal to this instance
1054 */
1055 public boolean equals( Object other )
1056 {
1057 if( null == other )
1058 {
1059 return false;
1060 }
1061 if( other instanceof Construct )
1062 {
1063 Construct construct = (Construct) other;
1064 if( !equals( m_target, construct.m_target ) )
1065 {
1066 return false;
1067 }
1068 if( m_compound != construct.m_compound )
1069 {
1070 return false;
1071 }
1072 if( !equals( m_method, construct.m_method ) )
1073 {
1074 return false;
1075 }
1076 if( m_compound )
1077 {
1078 return Arrays.equals( m_args, construct.m_args );
1079 }
1080 else
1081 {
1082 return equals( m_value, construct.m_value );
1083 }
1084 }
1085 else
1086 {
1087 return false;
1088 }
1089 }
1090
1091 /**
1092 * Compute the instance hashcode value.
1093 * @return the hashcode
1094 */
1095 public int hashCode()
1096 {
1097 int hash = 0;
1098 if( null != m_target )
1099 {
1100 hash ^= m_target.hashCode();
1101 }
1102 if( null != m_method )
1103 {
1104 hash ^= m_method.hashCode();
1105 }
1106 if( m_compound )
1107 {
1108 for( int i=0; i<m_args.length; i++ )
1109 {
1110 hash ^= m_args[i].hashCode();
1111 }
1112 }
1113 else
1114 {
1115 if( m_value != null )
1116 {
1117 hash ^= m_value.hashCode();
1118 }
1119 }
1120 return hash;
1121 }
1122
1123 private boolean equals( Object a, Object b )
1124 {
1125 if( null == a )
1126 {
1127 return ( null == b );
1128 }
1129 else
1130 {
1131 return a.equals( b );
1132 }
1133 }
1134 }